package com.example.cxx.myapplication;

/**
 *
 */



import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;


/**
 * The Class CircularProgressBar.
 * 圆形滚动进度条
 *
 * @author Guanyu.Guo
 * @since 09.13.2014
 *
 * @version 1.0 (09.13.2014)
 */
public class CircularProgressBar extends View {

    /**
     * The Constant TAG.
     */
    private static final String TAG = CircularProgressBar.class
            .getSimpleName();

    /**
     * The stroke width used to paint the circle.
     */
    private int mCircleStrokeWidth = 3;

    /**
     * The space between circle and view
     */
    private int mMarginSize = 20;

    /**
     * The rectangle enclosing the circle.
     */
    private final RectF mCircleBounds = new RectF();

    /**
     * Radius of the circle
     *
     * <p>
     * Note: (Re)calculated in {@link #onMeasure(int, int)}.
     * </p>
     */
    private float mRadius;

    /**
     * Radius of the circle
     *
     * <p>
     * Note: (Re)calculated in {@link #onMeasure(int, int)}.
     * </p>
     */
    private int mStartDegree = 270;

    /**
     * the color of the progress.
     */
    private int mProgressColor;

    /**
     * paint for the progress.
     */
    private Paint mProgressColorPaint;

    /**
     * The color of the progress background.
     */
    private int mProgressBackgroundColor;

    /**
     * the paint for the background.
     */
    private Paint mBackgroundColorPaint = new Paint();

    /**
     * The current progress.
     */
    private float mProgress = 0.3f;

    /**
     * The gravity of the view. Where should the Circle be drawn within the
     * given bounds
     *
     * {@link #computeInsets(int, int)}
     */
    private final int mGravity;

    /**
     * The Horizontal inset calcualted in {@link #computeInsets(int, int)}
     * depends on {@link #mGravity}.
     */
    private int mHorizontalInset = 0;

    /**
     * The Vertical inset calcualted in {@link #computeInsets(int, int)} depends
     * on {@link #mGravity}..
     */
    private int mVerticalInset = 0;

    /**
     * The Translation offset x which gives us the ability to use our own
     * coordinates system.
     */
    private float mTranslationOffsetX;

    /**
     * The Translation offset y which gives us the ability to use our own
     * coordinates system.
     */
    private float mTranslationOffsetY;

    /**
     * Instantiates a new holo circular progress bar.
     *
     * @param context
     *            the context
     */
    public CircularProgressBar(final Context context) {
        this(context, null);
    }

    /**
     * Instantiates a new holo circular progress bar.
     *
     * @param context
     *            the context
     * @param attrs
     *            the attrs
     */
    public CircularProgressBar(final Context context,
                               final AttributeSet attrs) {
        this(context, attrs, R.attr.circularProgressBarStyle);
    }

    /**
     * Instantiates a new holo circular progress bar.
     *
     * @param context
     *            the context
     * @param attrs
     *            the attrs
     * @param defStyle
     *            the def style
     */
    public CircularProgressBar(final Context context,
                               final AttributeSet attrs, final int defStyle) {
        super(context, attrs, defStyle);

        // load the styled attributes and set their properties
        final TypedArray attributes = context.obtainStyledAttributes(attrs,
                R.styleable.CircularProgressBar, defStyle, 0);

        setWheelSize((int) attributes.getDimension(
                R.styleable.CircularProgressBar_stroke_width, mCircleStrokeWidth));
        setMarginSize((int) attributes.getDimension(
                R.styleable.CircularProgressBar_margin_width, 0));
        setProgressColor(attributes.getColor(
                R.styleable.CircularProgressBar_progress_color, Color.CYAN));
        setBackgroundProgressColor(attributes.getColor(
                R.styleable.CircularProgressBar_progress_background_color, Color.BLACK));
        setProgress(attributes.getFloat(
                R.styleable.CircularProgressBar_progress, 0.0f));
        mGravity = attributes.getInt(
                R.styleable.CircularProgressBar_android_gravity,
                Gravity.CENTER);
        attributes.recycle();

    }

    /**
     * Compute insets.
     *
     * <pre>
     *  ______________________
     * |_________dx/2_________|
     * |......| /'''''\|......|
     * |-dx/2-|| View ||-dx/2-|
     * |______| \_____/|______|
     * |________ dx/2_________|
     * </pre>
     *
     * @param dx
     *            the dx the horizontal unfilled space
     * @param dy
     *            the dy the horizontal unfilled space
     */
    @SuppressLint("NewApi")
    private void computeInsets(final int dx, final int dy) {
        final int layoutDirection;
        int absoluteGravity = mGravity;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            layoutDirection = getLayoutDirection();
            absoluteGravity = Gravity.getAbsoluteGravity(mGravity,
                    layoutDirection);
        }

        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
            case Gravity.START:
                mHorizontalInset = 0;
                break;
            case Gravity.END:
                mHorizontalInset = dx;
                break;
            case Gravity.CENTER_HORIZONTAL:
            default:
                mHorizontalInset = dx / 2;
                break;
        }
        switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
            case Gravity.TOP:
                mVerticalInset = 0;
                break;
            case Gravity.BOTTOM:
                mVerticalInset = dy;
                break;
            case Gravity.CENTER_VERTICAL:
            default:
                mVerticalInset = dy / 2;
                break;
        }
    }

    /**
     * Gets the current rotation.
     *
     * @return the current rotation
     */
    private float getCurrentRotation() {
        return 360 * mProgress;
    }

    /**
     * gives the current progress of the ProgressBar. Value between 0..1 if you
     * set the progress to >1 you'll get progress % 1 as return value
     *
     * @return the progress
     */
    public float getProgress() {
        return mProgress;
    }

    /**
     * Gets the progress color.
     *
     * @return the progress color
     */
    public int getProgressColor() {
        return mProgressColor;
    }

    /*
     * (non-Javadoc)
     *
     * @see android.view.View#onDraw(android.graphics.Canvas)
     */
    @Override
    protected void onDraw(final Canvas canvas) {

        // All of our positions are using our internal coordinate system.
        // Instead of translating
        // them we let Canvas do the work for us.
        canvas.translate(mTranslationOffsetX, mTranslationOffsetY);

        final float progressRotation = getCurrentRotation();

        // draw the progress or a full circle if overdraw is true
        canvas.drawArc(mCircleBounds, mStartDegree, progressRotation,
                false, mProgressColorPaint);
        canvas.drawArc(mCircleBounds, 270, -(360 - progressRotation),
                false, mBackgroundColorPaint);
//		Log.e(TAG,"progressRotation: "+progressRotation);
//		Log.e(TAG,"ondraw");
    }

    /*
     * (non-Javadoc)
     *
     * @see android.view.View#onMeasure(int, int)
     */
    @Override
    protected void onMeasure(final int widthMeasureSpec,
                             final int heightMeasureSpec) {
        final int height = getDefaultSize(getSuggestedMinimumHeight(),
                heightMeasureSpec);
        final int width = getDefaultSize(getSuggestedMinimumWidth(),
                widthMeasureSpec);
        final int min = Math.min(width, height);
        setMeasuredDimension(min, height);

        final float halfWidth = min * 0.5f;
        mRadius = halfWidth - mMarginSize;

        mCircleBounds.set(-mRadius-2, -mRadius-2, mRadius+2, mRadius+2);

        computeInsets(width - min, height - min);

        mTranslationOffsetX = halfWidth + mHorizontalInset;
        mTranslationOffsetY = halfWidth + mVerticalInset;

    }

    /**
     * Sets the progress.
     *
     * @param progress
     *            the new progress
     */
    public void setProgress(final float progress) {
        if (progress == mProgress) {
            return;
        }

        if (progress == 1) {
            mProgress = 1;

        } else if (progress >= 1) {

            mProgress = progress % 1.0f;
        } else {
            mProgress = progress;
        }
//
//		if (!mIsInitializing) {
//			invalidate();
//		}
        invalidate();
    }

    /**
     * Sets the progress color.
     *
     * @param color
     *            the new progress color
     */
    public void setProgressColor(final int color) {
        mProgressColor = color;
        updateProgressColor();
    }

    /**
     * Sets the background color.
     *
     * @param color
     *            the new progress color
     */
    public void setBackgroundProgressColor(final int color) {
        mProgressBackgroundColor = color;
        updateBackgroundColor();
    }

    /**
     * Reverse the background color and progress color.
     *
     * @param color
     *            the new progress color
     */
    public void reverseProgressColor() {
        int color = mProgressColor;
        mProgressColor = mProgressBackgroundColor;
        mProgressBackgroundColor = color;
        updateProgressColor();
        updateBackgroundColor();
        invalidate();
    }

    /**
     * Sets the wheel size.
     *
     * @param dimension
     *            the new wheel size
     */
    public void setWheelSize(final int dimension) {
        Log.d(TAG, "setWheelSize: " + dimension);
        mCircleStrokeWidth = dimension;
    }

    /**
     * Sets the startDegree, default is 270.
     *
     * @param dimension
     *            the new wheel size
     */
    public void setStartDegree(final int startDegree) {
        mStartDegree = startDegree;
    }

    /**
     * Sets the margin size.
     *
     * @param dimension
     *            the new wheel size
     */
    public void setMarginSize(final int dimension) {
        mMarginSize = dimension;
    }

    /**
     * updates the paint of the progress and the thumb to give them a new visual
     * style
     */
    private void updateProgressColor() {
        mProgressColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mProgressColorPaint.setColor(mProgressColor);
        mProgressColorPaint.setStyle(Paint.Style.STROKE);
        mProgressColorPaint.setStrokeWidth(mCircleStrokeWidth);
    }

    /**
     * updates the paint of the background
     */
    private void updateBackgroundColor() {
        mBackgroundColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBackgroundColorPaint.setColor(mProgressBackgroundColor);
        mBackgroundColorPaint.setStyle(Paint.Style.STROKE);
        mBackgroundColorPaint.setStrokeWidth(mCircleStrokeWidth);
    }

    @SuppressLint("NewApi")
    public void animate(final CircularProgressBar progressBar, final Animator.AnimatorListener listener,
                        final float progress, final int duration) {
        animate(progressBar, listener, 0f, progress, duration);
    }

    @SuppressLint("NewApi")
    public void animate(final CircularProgressBar progressBar, final Animator.AnimatorListener listener, final float starProgress,
                        final float endProgress, final int duration) {
        animate(progressBar, listener, starProgress, endProgress, 0, duration);
    }

    @SuppressLint("NewApi")
    public void animate(final CircularProgressBar progressBar, final Animator.AnimatorListener listener, final float starProgress,
                        final float endProgress, final int startDelay, final int duration) {

        ObjectAnimator mProgressBarAnimator = ObjectAnimator.ofFloat(progressBar, "progress", starProgress, endProgress);
        mProgressBarAnimator.setStartDelay(startDelay);
        mProgressBarAnimator.setDuration(duration);
        if (listener != null) {
            mProgressBarAnimator.addListener(listener);
        }
//		mProgressBarAnimator.reverse();
        mProgressBarAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(final ValueAnimator animation) {
                progressBar.setProgress((Float) animation.getAnimatedValue());
            }
        });
        mProgressBarAnimator.start();
    }
}

